package com.jingdianjichi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;


import com.jingdianjichi.subject.common.entity.PageResult;
import com.jingdianjichi.subject.common.enums.IsDeletedFlageEnum;
import com.jingdianjichi.subject.common.util.IdWorkerUtil;
import com.jingdianjichi.subject.common.util.LoginUtil;
import com.jingdianjichi.subject.domain.convert.SubjectInfoConverter;

import com.jingdianjichi.subject.domain.entity.SubjectInfoBo;

import com.jingdianjichi.subject.domain.entity.SubjectOptionBo;
import com.jingdianjichi.subject.domain.handler.subject.SubjectTypeHandler;
import com.jingdianjichi.subject.domain.handler.subject.SubjectTypeHandlerFactory;
import com.jingdianjichi.subject.domain.redis.RedisUtil;
import com.jingdianjichi.subject.domain.service.SubjectInfoDomainService;

import com.jingdianjichi.subject.domain.service.SubjectLikedDomainService;
import com.jingdianjichi.subject.infra.basic.entity.SubjectInfo;

import com.jingdianjichi.subject.infra.basic.entity.SubjectInfoEs;
import com.jingdianjichi.subject.infra.basic.entity.SubjectLabel;
import com.jingdianjichi.subject.infra.basic.entity.SubjectMapping;
import com.jingdianjichi.subject.infra.basic.service.*;

import com.jingdianjichi.subject.infra.entity.UserInfo;
import com.jingdianjichi.subject.infra.rpc.UserRpc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


import javax.annotation.Resource;

import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {

    @Resource
    private SubjectInfoService subjectInfoService;
    @Resource
    private SubjectLabelService subjectLabelService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectTypeHandlerFactory subjectTypeHandlerFactory;
    @Resource
    private SubjectEsService subjectEsService;
     @Resource
     private UserRpc userRpc;
     @Resource
     private RedisUtil redisUtil;
     @Resource
     private SubjectLikedDomainService subjectLikedDomainService;
     private static final String RANK_KEY = "subject_rank";
    @Transactional(rollbackFor = Exception.class)
    public void add(SubjectInfoBo subjectInfoBo) {
        if (log.isInfoEnabled()) {
            log.info("SubjectInfoDomainServiceImpl.add.Bo:{}", JSON.toJSONString(subjectInfoBo));
        }
        //工厂+策略模式
        //一个工厂 包含了4种类型 根据传入的type 自动映射选择处理
        SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBo);
        //逻辑删除
        subjectInfo.setIsDeleted(IsDeletedFlageEnum.UN_DELETE.getCode());
        //id 是新增数据的id
        Long id = subjectInfoService.insert(subjectInfo);

        //根据类型获取对应的工厂方法
        SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());
        subjectInfoBo.setId(id);
        handler.add(subjectInfoBo);

        //映射表subject_mapping插入
        List<Integer> categoryIds = subjectInfoBo.getCategoryIds();
        List<Integer> labelIds = subjectInfoBo.getLabelIds();
        List<SubjectMapping> subjectMappingList = new LinkedList<>();
        categoryIds.forEach(categoryId -> {
            labelIds.forEach(labelId -> {
                SubjectMapping subjectMapping = new SubjectMapping();
                subjectMapping.setSubjectId(subjectInfo.getId());
                subjectMapping.setCategoryId(Long.valueOf(categoryId));
                subjectMapping.setLabelId(Long.valueOf(labelId));
                subjectMapping.setIsDeleted(IsDeletedFlageEnum.UN_DELETE.getCode());
                subjectMappingList.add(subjectMapping);
            });
        });
        subjectMappingService.batchInsert(subjectMappingList);
        //同步到es
        SubjectInfoEs subjectInfoEs = new SubjectInfoEs();
        subjectInfoEs.setDocId(new IdWorkerUtil(1,1,1).nextId());
        subjectInfoEs.setSubjectId(subjectInfo.getId());
        subjectInfoEs.setSubjectAnswer(subjectInfoBo.getSubjectAnswer());
        subjectInfoEs.setCreateTime(new Date().getTime());
        subjectInfoEs.setCreateUser("鸡翅");
        subjectInfoEs.setSubjectName(subjectInfo.getSubjectName());
        subjectInfoEs.setSubjectType(subjectInfo.getSubjectType());
        subjectEsService.insert(subjectInfoEs);
         //redis放入zset 计入排行榜
        //每添加一题，向key为subject_rank的zset中，添加LoginId，分数为+1
        redisUtil.addScore(RANK_KEY, LoginUtil.getLoginId(),1);

    }

    @Override
    public PageResult<SubjectInfoBo> getSubjectPage(SubjectInfoBo subjectInfoBo) {
        if (log.isInfoEnabled()) {
            log.info("SubjectInfoDomainServiceImpl.getSubjectPage.Bo:{}", JSON.toJSONString(subjectInfoBo));
        }
        PageResult<SubjectInfoBo> pageResult = new PageResult<>();
        pageResult.setPageNo(subjectInfoBo.getPageNo());
        pageResult.setPageSize(subjectInfoBo.getPageSize());
        //起始页
        int start = (subjectInfoBo.getPageNo() - 1) * subjectInfoBo.getPageSize();
        SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBo);
        int count = subjectInfoService.countByCondition(subjectInfo, subjectInfoBo.getCategoryId(), subjectInfoBo.getLabelId());
        if (count == 0) {
            return pageResult;
        }
        List<SubjectInfo> subjectInfoList = subjectInfoService.queryPage(subjectInfo,
                subjectInfoBo.getCategoryId(),
                subjectInfoBo.getLabelId(),
                start, subjectInfoBo.getPageSize());
        List<SubjectInfoBo> subjectInfoBoList = SubjectInfoConverter.INSTANCE.convertListBoToInfo(subjectInfoList);
        pageResult.setResult(subjectInfoBoList);
        pageResult.setTotal(count);
        return pageResult;
    }

    @Override
    public SubjectInfoBo querySubjectInfo(SubjectInfoBo subjectInfoBo) {
        if (log.isInfoEnabled()) {
            log.info("SubjectInfoDomainServiceImpl.querySubjectInfo.Bo:{}", JSON.toJSONString(subjectInfoBo));
        }
        SubjectInfo subjectInfo = subjectInfoService.queryById(subjectInfoBo.getId());

        SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());
        SubjectOptionBo optionBo = handler.queue(subjectInfo.getId());
        SubjectInfoBo bo = SubjectInfoConverter.INSTANCE.convertOptionAndInfoToBo(optionBo, subjectInfo);
        //查询题目标签 从subject_mapping 表中差
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setSubjectId(subjectInfo.getId());
        subjectMapping.setIsDeleted(IsDeletedFlageEnum.UN_DELETE.getCode());
        List<SubjectMapping> subjectMappingList = subjectMappingService.queryLabelId(subjectMapping);
        List<Long> labelIdList = subjectMappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        //从subject_label 表中查出 labelName
        List<SubjectLabel> subjectLabelList = subjectLabelService.batchQueryById(labelIdList);
        List<String> labelNameList = subjectLabelList.stream().map(SubjectLabel::getLabelName).collect(Collectors.toList());
        bo.setLabelName(labelNameList);
        //是否被点赞，点赞数量
        bo.setLiked(subjectLikedDomainService.isLiked(subjectInfo.getId().toString(), LoginUtil.getLoginId()));
        bo.setLikedCount(subjectLikedDomainService.getLikedCount(subjectInfo.getId().toString()));
       //实现上一题，下一题切换
        assembleSubjectCursor(subjectInfoBo ,bo);
        return bo;
    }
    private void assembleSubjectCursor(SubjectInfoBo subjectInfoBO, SubjectInfoBo bo) {
        Long categoryId = subjectInfoBO.getCategoryId();
        Long labelId = subjectInfoBO.getLabelId();
        Long subjectId = subjectInfoBO.getId();
        if (Objects.isNull(categoryId) || Objects.isNull(labelId)) {
            return;
        }
        Long nextSubjectId = subjectInfoService.querySubjectIdCursor(subjectId, categoryId, labelId, 1);
        bo.setNextSubjectId(nextSubjectId);
        Long lastSubjectId = subjectInfoService.querySubjectIdCursor(subjectId, categoryId, labelId, 0);
        bo.setLastSubjectId(lastSubjectId);
    }


    @Override
    public PageResult<SubjectInfoEs> getSubjectPageBySearch(SubjectInfoBo subjectInfoBo) {
      SubjectInfoEs subjectInfoEs = new SubjectInfoEs();
      subjectInfoEs.setPageNo(subjectInfoBo.getPageNo());
      subjectInfoEs.setPageSize(subjectInfoBo.getPageSize());
      subjectInfoEs.setKeyWord(subjectInfoBo.getKeyWord());
        return subjectEsService.querySubjectList(subjectInfoEs);
    }

    //获取题目贡献榜
    @Override
    public List<SubjectInfoBo> getContributeList() {
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisUtil.rankWithScore(RANK_KEY, 0L, 5L);
        if (log.isInfoEnabled()){
            log.info("getContributeList.typedTuples:{}",JSON.toJSONString(typedTuples));
        }
        if (CollectionUtils.isEmpty(typedTuples)){
            return Collections.emptyList();
        }
        List<SubjectInfoBo> boList = new LinkedList<>();
        typedTuples.forEach(rank -> {
            SubjectInfoBo subjectInfoBo = new SubjectInfoBo();
            subjectInfoBo.setSubjectCount(rank.getScore().intValue());
            UserInfo userInfo = userRpc.getUserInfo(rank.getValue());
            subjectInfoBo.setCreateUser(userInfo.getNickName());
            subjectInfoBo.setCreateUserAvatar(userInfo.getAvatar());
            boList.add(subjectInfoBo);
        });
        return boList;
        //数据库方式
//        List<SubjectInfo> subjectInfoList =  subjectInfoService.getContributeCount();
//      if (CollectionUtils.isEmpty(typedTuples)){
//          return Collections.emptyList();
//      }
//      List<SubjectInfoBo> boList = new LinkedList<>();
//      subjectInfoList.forEach(subjectInfo -> {
//          SubjectInfoBo subjectInfoBo = new SubjectInfoBo();
//           subjectInfoBo.setSubjectCount(subjectInfo.getSubjectCount());
//          UserInfo userInfo = userRpc.getUserInfo(subjectInfo.getCreatedBy());
//          subjectInfoBo.setCreateUser(userInfo.getNickName());
//          subjectInfoBo.setCreateUserAvatar(userInfo.getAvatar());
//          boList.add(subjectInfoBo);
//      });
//        return boList;
    }


}
